package com.stock.service.impl;

import com.google.common.collect.Lists;
import com.stock.constant.ParseType;
import com.stock.mapper.StockBlockRtInfoMapper;
import com.stock.mapper.StockBusinessMapper;
import com.stock.mapper.StockMarketIndexInfoMapper;
import com.stock.mapper.StockRtInfoMapper;
import com.stock.pojo.entity.StockBlockRtInfo;
import com.stock.pojo.entity.StockMarketIndexInfo;
import com.stock.pojo.entity.StockRtInfo;
import com.stock.pojo.vo.StockInfoConfig;
import com.stock.service.StockTimerTaskService;
import com.stock.utils.DateTimeUtil;
import com.stock.utils.IdWorker;
import com.stock.utils.ParserStockInfoUtil;
import lombok.extern.slf4j.Slf4j;
import org.joda.time.DateTime;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

import javax.annotation.PostConstruct;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

@Service
@Slf4j
public class StockTimerTaskServiceImpl implements StockTimerTaskService {

    @Autowired
    private StockInfoConfig stockInfoConfig;

    @Autowired
    private RestTemplate restTemplate;

    @Autowired
    private IdWorker idWorker;

    @Autowired
    private StockMarketIndexInfoMapper stockMarketIndexInfoMapper;

    @Autowired
    private ParserStockInfoUtil parserStockInfoUtil;

    @Autowired
    private StockRtInfoMapper stockRtInfoMapper;

    @Autowired
    private StockBusinessMapper stockBusinessMapper;

    @Autowired
    private RabbitTemplate rabbitTemplate;

    //全局请求头
    private HttpEntity httpEntity;

    @Autowired
    private StockBlockRtInfoMapper stockBlockRtInfoMapper;

    //TODO 初始化构造方法时执行这个函数体，避免每次都去请求
    @PostConstruct
    public void initData() {
        //组装请求头
        HttpHeaders headers = new HttpHeaders();
        //填写新浪规定的防盗链参数，不然访问不到
        headers.add("Referer", "https://finance.sina.com.cn/stock/");
        headers.add("User-Agent", "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36");
        //组装请求对象
        httpEntity = new HttpEntity<>(headers);
    }

    //TODO 定义采集股票数据的定时任务的服务
    @Override
    public void getInnerMarketInfo() {
        //1.定义采集的url地址
        String url = stockInfoConfig.getMarketUrl() + String.join(",", stockInfoConfig.getInner());

        /*
        //2.调用RestTemplate采集数据
        //2.1 组装请求头
        HttpHeaders headers = new HttpHeaders();
        //2.2 填写新浪规定的防盗链参数，不然访问不到
        headers.add("Referer", "https://finance.sina.com.cn/stock/");
        headers.add("User-Agent", "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36");
        //2.3 组装请求对象
        HttpEntity<Object> httpEntity = new HttpEntity<>(headers);
         */

        //2.4 RestTemplate发起请求
        ResponseEntity<String> responseEntity = restTemplate.exchange(url, HttpMethod.GET, httpEntity, String.class);
        //2.5 获取js格式数据
        String jsData = responseEntity.getBody();

        //3.TODO 数据解析（重要）
        /*
        var hq_str_sh000001="上证指数,3267.8103,3283.4261,3236.6951,3290.2561,3236.4791,
        0,0,402626660,398081845473,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
        2022-04-07,15:01:09,00";

        var hq_str_sz399001="深证成指,12101.371,12172.911,11972.023,12205.097,11971.334,
        0.000,0.000,47857870369,524892592190.995,0,0.000,0,0.000,0,0.000,0,0.000,0,0.000,0,0.000,0,0.000,0,0.000,0,0.000,0,0.000,
        2022-04-07,15:00:03,00";
         */
        //3.1 编写正则表达式 -- 第一个（）里面内容是sh000001，第二个（）里面内容是后面一串的数据
        String regex = "var hq_str_(.+)=\"(.+)\";";
        //3.2 编译表达式，获取编译对象
        Pattern pattern = Pattern.compile(regex);
        //3.3 匹配字符串
        Matcher matcher = pattern.matcher(jsData);
        //收集所有大盘数据
        ArrayList<StockMarketIndexInfo> infos = new ArrayList<>();
        //3.4 循环匹配，获取数据
        while (matcher.find()) {
            //获取大盘的code
            String marketCode = matcher.group(1);
            //获取其它信息，字符串以逗号间隔
            String otherInfo = matcher.group(2);
            //以逗号切割字符串，形成数组
            String[] splitArr = otherInfo.split(",");
            //大盘名称
            String marketName = splitArr[0];
            //获取当前大盘的开盘点数
            BigDecimal openPoint = new BigDecimal(splitArr[1]);
            //前收盘点
            BigDecimal preClosePoint = new BigDecimal(splitArr[2]);
            //获取大盘的当前点数
            BigDecimal curPoint = new BigDecimal(splitArr[3]);
            //获取大盘最高点
            BigDecimal maxPoint = new BigDecimal(splitArr[4]);
            //获取大盘的最低点
            BigDecimal minPoint = new BigDecimal(splitArr[5]);
            //获取成交量
            Long tradeAmt = Long.valueOf(splitArr[8]);
            //获取成交金额
            BigDecimal tradeVol = new BigDecimal(splitArr[9]);
            //时间
            Date curTime = DateTimeUtil.getDateTimeWithoutSecond(splitArr[30] + " " + splitArr[31]).toDate();

            //组装entity对象
            StockMarketIndexInfo info = StockMarketIndexInfo.builder()
                    .id(idWorker.nextId())
                    .marketCode(marketCode)
                    .marketName(marketName)
                    .curPoint(curPoint)
                    .openPoint(openPoint)
                    .preClosePoint(preClosePoint)
                    .maxPoint(maxPoint)
                    .minPoint(minPoint)
                    .tradeVolume(tradeVol)
                    .tradeAmount(tradeAmt)
                    .curTime(curTime)
                    .build();
            //收集封装的对象，方便批量插入
            infos.add(info);
        }
        log.info("采集最新的大盘数据：{}", infos);
        //批量插入数据库中
        int count = stockMarketIndexInfoMapper.insertBatch(infos);
        if (count > 0) {
            log.info("批量插入成功，数量为：{}，当前时间：{}，数据：{}", count, DateTime.now().toString("yyyy-MM-dd HH:mm:ss"), infos);
            //通知后台终端刷新本地缓存，发送的日期数据是告知对方当前更新的股票数据所在时间点
            rabbitTemplate.convertAndSend("stockExchange","inner.market",new Date());
        } else {
            log.error("批量插入失败，当前时间：{}，数据：{}", DateTime.now().toString("yyyy-MM-dd HH:mm:ss"), infos);
        }
    }

    // 定义获取分钟级股票数据
    @Override
    public void getStockRtIndex() {
        //1.获取个股的编码
        List<String> allStockCode = stockBusinessMapper.getAllStockCode();
        //2.给各个股票添加前缀，并重新赋值给allStockCode
        allStockCode = allStockCode.stream()
                .map(code -> code.startsWith("6") ? "sh" + code : "sz" + code)
                .collect(Collectors.toList());
        //TODO
        // 3.核心思路：将大的集合切分成若干小的集合，分批次拉取数据（Lists来自于--guava）
        Lists.partition(allStockCode, 15).forEach(codes -> {
            //1.定义采集的url地址
            String url = stockInfoConfig.getMarketUrl() + String.join(",", codes);

            /*
            //2.调用RestTemplate采集数据
            //2.1 组装请求头
            HttpHeaders headers = new HttpHeaders();
            //2.2 填写新浪规定的防盗链参数，不然访问不到
            headers.add("Referer", "https://finance.sina.com.cn/stock/");
            headers.add("User-Agent", "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36");
            //2.3 组装请求对象
            HttpEntity<Object> entity = new HttpEntity<>(headers);
             */

            //2.4 RestTemplate发起请求
            ResponseEntity<String> responseEntity = restTemplate.exchange(url, HttpMethod.GET, httpEntity, String.class);
            //2.5 获取js格式数据
            String jsData = responseEntity.getBody();
            //TODO 调用工具类进行数据解析
            List<StockRtInfo> infos = parserStockInfoUtil.parser4StockOrMarketInfo(jsData, ParseType.ASHARE);
            log.info("采集最新的个股数据：{}", infos);
            //TODO 批量插入数据库中
            int count = stockRtInfoMapper.insertBatch(infos);
            if (count > 0) {
                log.info("批量插入成功，数量为：{}，当前时间：{}，数据：{}", count, DateTime.now().toString("yyyy-MM-dd HH:mm:ss"), infos);
            } else {
                log.error("批量插入失败，当前时间：{}，数据：{}", DateTime.now().toString("yyyy-MM-dd HH:mm:ss"), infos);
            }
        });
    }

    // 获取大盘板块的实时数据信息
    @Override
    public void getStockBlockInfo() {
        //1.定义采集的url地址
        String url = stockInfoConfig.getBlockUrl();
        //2.RestTemplate发起请求
        ResponseEntity<String> responseEntity = restTemplate.exchange(url, HttpMethod.GET, httpEntity, String.class);
        //3.获取js格式数据
        String jsData = responseEntity.getBody();
        //TODO 4.调用工具类进行数据解析
        List<StockBlockRtInfo> infos = parserStockInfoUtil.parse4StockBlock(jsData);
        log.info("采集最新的板块数据：{}", infos);
        //TODO 5.批量插入数据库中
        int count = stockBlockRtInfoMapper.insertBatch(infos);
    }

    @Override
    public void getStockOuterMarketInfo() {

    }

}
